﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using OpenCvSharp;
using OpenCvSharp.Dnn;
using OpenCvSharp.Extensions;
using WindowsFormsApp1.bookdemo;
using Size = OpenCvSharp.Size;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        Mat source = new Mat(@"1.jpg", ImreadModes.Color);
        Mat source2 = new Mat(@"2.jpg", ImreadModes.Color);
        Mat source3 = new Mat(@"3.jpg", ImreadModes.Color);
        Mat source4 = new Mat(@"4.jpg", ImreadModes.Color);
        Mat device = new Mat(@"device.png", ImreadModes.Color);
       
        Mat bur;
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
           
            Mat dest=new Mat();
           Rect rect = new Rect(225, 944, 160,  40);
            Mat cutImg = new Mat(source, rect);
            Cv2.CvtColor(cutImg, dest, ColorConversionCodes.BGR2GRAY);

          
           // ret, thresh = cv2.threshold(blurred, 150, 255, cv2.THRESH_BINARY)
            //二值化
            Mat binMat=new Mat();
             var thresh=Cv2.Threshold(dest, binMat, 200, 255, ThresholdTypes.Binary);
              Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5));

              Mat closed = new Mat();
               Cv2.MorphologyEx(binMat, closed, MorphTypes.Close,kernel);

            var edge = new Mat();
            Cv2.Canny(closed,edge,50,150);

            //kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 25))
            //closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)


            var match = MatchPicBySift(source, cutImg);
            OpenCvSharp.Point[][] pointses;
            HierarchyIndex[] hierarchyIndexs;
            Mat contours = cutImg.Clone();
            Cv2.FindContours(binMat,out pointses,out hierarchyIndexs,RetrievalModes.CComp,ContourApproximationModes.ApproxNone);
            for (int i = 0; i < pointses.Length; i++)
            {
                  // Cv2.DrawContours(contours, pointses,i,new Scalar(0,255,0));
                //if (Cv2.ContourArea(pointses[i]) < 10)
                //{
                //    continue;
                //}

                var bRect= Cv2.BoundingRect(pointses[i]);
                if (bRect.Size.Height < 10 && bRect.Size.Height < 10)
                {
                    continue;
                }

                Cv2.Rectangle(contours,bRect,new Scalar(0,255,0));

            }

           
          
           Cv2.ImShow("Demo", dest);
            Cv2.ImShow("Demo2", cutImg);
            Cv2.ImShow("binMat", binMat);
            Cv2.ImShow("contours", contours);
            Cv2.ImShow("kernel", kernel);
          //  Cv2.ImShow("kernel", kernel);
          //  Cv2.ImShow("morphologMat", edge);
            //Cv2.ImShow("Demo4", match);
            Cv2.WaitKey(0);
        }
        public Bitmap MatToBitmap(Mat image)
        {
            return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image);
        }

        public  Bitmap MatchPicBySurf(Bitmap imgSrc, Bitmap imgSub, double threshold = 400)
        {
            using (Mat matSrc = imgSrc.ToMat())
            using (Mat matTo = imgSub.ToMat())
            using (Mat matSrcRet = new Mat())
            using (Mat matToRet = new Mat())
            {
                KeyPoint[] keyPointsSrc, keyPointsTo;
                using (var surf = OpenCvSharp.XFeatures2D.SURF.Create(threshold, 4, 3, true, true))
                {
                    surf.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);
                    surf.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);
                }

                using (var flnMatcher = new OpenCvSharp.FlannBasedMatcher())
                {
                    var matches = flnMatcher.Match(matSrcRet, matToRet);
                    //求最小最大距离
                    double minDistance = 1000;//反向逼近
                    double maxDistance = 0;
                    for (int i = 0; i < matSrcRet.Rows; i++)
                    {
                        double distance = matches[i].Distance;
                        if (distance > maxDistance)
                        {
                            maxDistance = distance;
                        }
                        if (distance < minDistance)
                        {
                            minDistance = distance;
                        }
                    }
                    Console.WriteLine($"max distance : {maxDistance}");
                    Console.WriteLine($"min distance : {minDistance}");

                    var pointsSrc = new List<Point2f>();
                    var pointsDst = new List<Point2f>();
                    //筛选较好的匹配点
                    var goodMatches = new List<DMatch>();
                    for (int i = 0; i < matSrcRet.Rows; i++)
                    {
                        double distance = matches[i].Distance;
                        if (distance < Math.Max(minDistance * 2, 0.02))
                        {
                            pointsSrc.Add(keyPointsSrc[matches[i].QueryIdx].Pt);
                            pointsDst.Add(keyPointsTo[matches[i].TrainIdx].Pt);
                            //距离小于范围的压入新的DMatch
                            goodMatches.Add(matches[i]);
                        }
                    }

                    var outMat = new Mat();

                    // 算法RANSAC对匹配的结果做过滤
                    
                      var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
                    var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
                    var outMask = new Mat();
                    // 如果原始的匹配结果为空, 则跳过过滤步骤
                    if (pSrc.Count > 0 && pDst.Count > 0)
                        Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
                    // 如果通过RANSAC处理后的匹配点大于10个,才应用过滤. 否则使用原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果).
                    if (outMask.Rows > 10)
                    {
                        byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];
                        outMask.GetArray(0, 0, maskBytes);
                        Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints);
                    }
                    else
                        Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);
                    return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(outMat);
                }
            }
        }

        private static Point2d Point2fToPoint2d(Point2f input)
        {
            return new Point2d(input.X,input.Y);

        }

        public static Bitmap MatchPicBySift(Bitmap imgSrc, Bitmap imgSub)
        {
            using (Mat matSrc = imgSrc.ToMat())
            using (Mat matTo = imgSub.ToMat())
            using (Mat matSrcRet = new Mat())
            using (Mat matToRet = new Mat())
            {
                KeyPoint[] keyPointsSrc, keyPointsTo;
                using (var sift = OpenCvSharp.XFeatures2D.SIFT.Create())
                {
                    sift.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);
                    sift.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);
                }
                using (var bfMatcher = new OpenCvSharp.BFMatcher())
                {
                    var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);

                    var pointsSrc = new List<Point2f>();
                    var pointsDst = new List<Point2f>();
                    var goodMatches = new List<DMatch>();
                    foreach (DMatch[] items in matches.Where(x => x.Length > 1))
                    {
                        if (items[0].Distance < 0.5 * items[1].Distance)
                        {
                            pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
                            pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
                            goodMatches.Add(items[0]);
                            Console.WriteLine($"{keyPointsSrc[items[0].QueryIdx].Pt.X}, {keyPointsSrc[items[0].QueryIdx].Pt.Y}");
                        }
                    }

                    var outMat = new Mat();

                    // 算法RANSAC对匹配的结果做过滤
                    var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
                    var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
                    var outMask = new Mat();
                    // 如果原始的匹配结果为空, 则跳过过滤步骤
                    if (pSrc.Count > 0 && pDst.Count > 0)
                        Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
                    // 如果通过RANSAC处理后的匹配点大于10个,才应用过滤. 否则使用原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果).
                    if (outMask.Rows > 10)
                    {
                        byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];
                        outMask.GetArray(0, 0, maskBytes);
                        Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints);
                    }
                    else
                        Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);
                    return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(outMat);
                }
            }
        }


        public static Mat MatchPicBySift(Mat matSrc, Mat matTo)
        {
          
            using (Mat matSrcRet = new Mat())
            using (Mat matToRet = new Mat())
            {
                KeyPoint[] keyPointsSrc, keyPointsTo;
                using (var sift = OpenCvSharp.XFeatures2D.SIFT.Create())
                {
                    sift.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);
                    sift.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);
                }
                using (var bfMatcher = new OpenCvSharp.BFMatcher())
                {
                    var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);

                    var pointsSrc = new List<Point2f>();
                    var pointsDst = new List<Point2f>();
                    var goodMatches = new List<DMatch>();
                    foreach (DMatch[] items in matches.Where(x => x.Length > 1))
                    {
                        if (items[0].Distance < 0.5 * items[1].Distance)
                        {
                            pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
                            pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
                            goodMatches.Add(items[0]);
                            Console.WriteLine($"{keyPointsSrc[items[0].QueryIdx].Pt.X}, {keyPointsSrc[items[0].QueryIdx].Pt.Y}");
                        }
                    }

                    var outMat = new Mat();

                    // 算法RANSAC对匹配的结果做过滤
                    var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
                    var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
                    var outMask = new Mat();
                    // 如果原始的匹配结果为空, 则跳过过滤步骤
                    if (pSrc.Count > 0 && pDst.Count > 0)
                        Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
                    // 如果通过RANSAC处理后的匹配点大于10个,才应用过滤. 否则使用原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果).
                    if (outMask.Rows > 10)
                    {
                        byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];
                        outMask.GetArray(0, 0, maskBytes);
                        Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints);
                    }
                    else
                        Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);
                    return outMat;
                }
            }
        }
        private TemplateMatchModes templateMatchModes= TemplateMatchModes.CCoeff;
        public  System.Drawing.Point FindPicFromImage(Bitmap imgSrc, Bitmap imgSub, double threshold = 0.9)
        {
            OpenCvSharp.Mat srcMat = null;
            OpenCvSharp.Mat dstMat = null;
            OpenCvSharp.OutputArray outArray = null;
         
            try
            {
                srcMat = imgSrc.ToMat();
                dstMat = imgSub.ToMat();
                outArray = OpenCvSharp.OutputArray.Create(srcMat);

                OpenCvSharp.Cv2.MatchTemplate(srcMat, dstMat, outArray, templateMatchModes);
                double minValue, maxValue;
                OpenCvSharp.Point location, point;
                OpenCvSharp.Cv2.MinMaxLoc(OpenCvSharp.InputArray.Create(outArray.GetMat()), out minValue, out maxValue, out location, out point);
                Console.WriteLine(maxValue);
                if (maxValue >= threshold)
                    return new System.Drawing.Point(point.X, point.Y);
                return System.Drawing.Point.Empty;
            }
            catch (Exception ex)
            {
                return System.Drawing.Point.Empty;
            }
            finally
            {
                if (srcMat != null)
                    srcMat.Dispose();
                if (dstMat != null)
                    dstMat.Dispose();
                if (outArray != null)
                    outArray.Dispose();
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
          
            var mats= Cv2.Split(source);
            int i = 0;
            foreach (var mat in mats)
            {
                i++;
                Cv2.ImShow($"split{i}", mat);
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            var mats = Cv2.Split(source);
            int i = 0;
            foreach (var mat in mats)
            {
                i++;
                Cv2.ImShow($"split{i}", mat);
            }
            var mats2 = new Mat[] { mats[0], mats[1], mats[1] };
            var matdst=new Mat();
            Cv2.Merge(mats2, matdst);
            Cv2.ImShow($"dst", matdst);
        }

        private void button4_Click(object sender, EventArgs e)
        {
           
            Mat dest = new Mat();
            Rect rect = new Rect(0, 800, source.Width, 400);
            Mat cutImg = new Mat(source, rect);
            Mat srcClone = cutImg;
            var mats = Cv2.Split(cutImg);

            var matblue = mats[1];
            Mat binMat = new Mat();
            var thresh = Cv2.Threshold(matblue, binMat, 70, 255, ThresholdTypes.Binary);
            Mat matNot=new Mat();
           Cv2.BitwiseNot(binMat, matNot);


            Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(20, 20));
            Mat closed = new Mat();
            Cv2.MorphologyEx(matNot, closed, MorphTypes.Close, kernel);


            Cv2.ImShow("binMat", closed);
            var edge = new Mat();
            Cv2.Canny(closed, edge, 50, 150);

            Cv2.ImShow("edge", edge);
            Mat contours = closed.Clone();
            OpenCvSharp.Point[][] pointses;
            HierarchyIndex[] hierarchyIndexs;
            Cv2.FindContours(contours, out pointses,       
               out hierarchyIndexs, RetrievalModes.CComp, ContourApproximationModes.ApproxSimple);
            for (int i = 0; i < pointses.Length; i++)
            {
                // Cv2.DrawContours(contours, pointses,i,new Scalar(0,255,0));
                //if (Cv2.ContourArea(pointses[i]) < 10)
                //{
                //    continue;
                //}

                var bRect = Cv2.BoundingRect(pointses[i]);
                if (bRect.Size.Width < 20 || bRect.Size.Height < 10)
                {
                    continue;
                }
                if (bRect.Size.Width > 200 || bRect.Size.Height > 50)
                {
                    continue;
                }
                var 宽高比 = bRect.Size.Width / bRect.Size.Height;
                if (宽高比 < 2 || 宽高比>15)
                {
                    continue;
                }
                Cv2.Rectangle(srcClone, bRect, new Scalar( 255,255,0));
              
               // Mat cutImg = new Mat(source, bRect);
               // Cv2.ImShow("marke"+i, cutImg);
            }

           Cv2.ImShow("marke", srcClone);

        }

        private void button5_Click(object sender, EventArgs e)
        {
           int channels= source.Channels();
            

            var vec3b = source.At<Vec3b>(100, 100);
            for (int i = 0; i < source.Width; i++)
            {
                source.Set<Vec3b>(100,i,  new Vec3b(0, 255, 0));
                 
                
            }
          
            Cv2.ImShow("Image", source);
        }

        private void 特征比对_Click(object sender, EventArgs e)
        {
         
          

            var match = MatchPicBySift(source2, 
                source4);
            Cv2.ImShow("image", match);
        }

        private void button7_Click(object sender, EventArgs e)
        {
           
        }

        private void button9_Click(object sender, EventArgs e)
        {
            Cv2.ImShow("Source", source);
        }

        private void button8_Click(object sender, EventArgs e)
        {
            Mat dst = new Mat();
            //注意：size 参数一定要是奇数 (均值模糊)
            Cv2.Blur(source3, dst, new Size(10, 10), new OpenCvSharp.Point(-1, -1));
            Cv2.ImShow("Blur", dst);
        }

        private void button10_Click(object sender, EventArgs e)
        {
            Histogram1D histogram = new Histogram1D();
            Mat dest = new Mat();
            Cv2.CvtColor(source3, dest, ColorConversionCodes.BGR2GRAY);
            var abc=histogram.GetHistorgramFloatArr(dest);
            Cv2.ImShow("Src", dest);
            this.chart1.Series[0].Points.Clear();
            chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
            chart1.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
            chart1.ChartAreas[0].CursorX.IsUserEnabled = true;
            for (int i = 0; i < abc.Count; i++)
            {
                chart1.Series[0].Points.Add(new DataPoint(i, abc[i]));
            }
           // this.chart1.Series[0].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;

        }

        private void button11_Click(object sender, EventArgs e)
        {
            HistogramColor histogram = new HistogramColor();
           
            var abc = histogram.GetHistorgramFloatArr(device);
            Cv2.ImShow("Src", device);
            this.chart1.Series[0].Points.Clear();
            chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
            chart1.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
            chart1.ChartAreas[0].CursorX.IsUserEnabled = true;
            for (int i = 0; i < abc.Count; i++)
            {
                chart1.Series[0].Points.Add(new DataPoint(i, abc[0][i]));
            }
        }
        private static readonly string[] Labels = { "background", 
            "aeroplane", "bicycle",
            "bird", "boat", "bottle",
            "bus", "car", "cat", "chair",
            "cow", "diningtable", "dog", "horse", "motorbike",
            "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor" };

        private void button12_Click(object sender, EventArgs e)
        {
            var org = source;

            var net =  CvDnn.ReadNetFromCaffe("prototxt", "model.txt");
            var blob=CvDnn.BlobFromImage(source);
            net.SetInput(blob);
            var prob = net.Forward();
           var p= prob.Reshape(1, prob.Size(2));

            for (int i = 0; i < prob.Size(2); i++)
            {
                var confidence = p.At<float>(i,2);
                if (confidence > 0.4)
                {
                    var idx = p.At<int>(i, 1);
                    var w1 = org.Width * p.At<int>(i, 3);
                    var h1 = org.Width * p.At<int>(i, 4);
                    var w2 = org.Width * p.At<int>(i, 5);
                    var h2 = org.Width * p.At<int>(i, 6);
                    Console.WriteLine();
                }
            }
            
        }

        private void btn均值漂移_Click(object sender, EventArgs e)
        {
           

                Mat srcHSV = new Mat();
                Mat roiHSV = new Mat();
                Cv2.CvtColor(source, srcHSV, ColorConversionCodes.BGR2HSV);//将图片转换成HSV空间
                Cv2.CvtColor(device, roiHSV, ColorConversionCodes.BGR2HSV);//将图片转换成HSV空间
                int[] histsize = new int[] { 256 };//一个通道，初始化为256箱子
                Rangef[] range = new Rangef[1];//一个通道，范围
                range[0].Start = 0.0F;//从0开始（含）
                range[0].End = 180.0F;//到180结束（不含，色调的范围0到180
                int[] channels = new int[] { 0 };//一个通道,初始化为通道0,这些东西可以共用设置

                Mat[] rois = Cv2.Split(roiHSV);//将roi拆分
                Mat[] rois0 = new Mat[] { rois[0] };//roi的第一个通道，也就是H，色调

                Mat mask = new Mat();//掩码;
              //  Cv2.Threshold(rois[1], mask, 65, 255, ThresholdTypes.BinaryInv);//过滤掉较低饱和度的像素

                Mat[] hist = new Mat[] { new Mat() };//一个矩阵数组，用来接收直方图,记得初始化
                Cv2.CalcHist(rois0, channels, mask, hist[0], 1, histsize, range);//把roi的色调通道转换成直方图

                Mat[] srcs = new Mat[] { srcHSV };
                Mat[] histBack = new Mat[] { new Mat() };//返回的反向直方图，一个通道就够
                Cv2.CalcBackProject(srcs, channels, hist[0], histBack[0], range);//输出反向直方图
            Rect rect = new Rect(0,0,device.Width,device.Height);

            Cv2.MeanShift(histBack[0], ref rect, new TermCriteria(CriteriaType.MaxIter, 10, 0.1));//框大小不会变化，其它一样
                                                                                                  //Cv2.CamShift(HistBack(dst, roi), ref rect, new TermCriteria(CriteriaType.MaxIter, 10, 0.1));//框大小会变化
            source.Rectangle(rect, Scalar.White);//在dst上画框
            Cv2.ImShow("dst", source);
            Cv2.ImShow("src", device);



        }

        private void button13_Click(object sender, EventArgs e)
        {
            Histogram1D histogram = new Histogram1D();
            Mat dest = new Mat();
            Cv2.CvtColor(device, dest, ColorConversionCodes.BGR2HSV);
            var abc = histogram.GetHistorgramFloatArr(dest);
            Cv2.ImShow("Src", device);
            Cv2.ImShow("dest", source3);
          
            this.chart1.Series[0].Points.Clear();
            chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
            chart1.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
            chart1.ChartAreas[0].CursorX.IsUserEnabled = true;
            for (int i = 0; i < abc.Count; i++)
            {
                chart1.Series[0].Points.Add(new DataPoint(i, abc[i]));
            }
        }

        private void button14_Click(object sender, EventArgs e)
        {

            Mat srcHSV = new Mat();
            Mat roiHSV = new Mat();
            Cv2.CvtColor(source, srcHSV, ColorConversionCodes.BGR2GRAY);//将图片转换成HSV空间
            Cv2.CvtColor(device, roiHSV, ColorConversionCodes.BGR2GRAY);//将图片转换成HSV空间
            int[] histsize = new int[] { 256 };//一个通道，初始化为256箱子
            Rangef[] range = new Rangef[1];//一个通道，范围
            range[0].Start = 0.0F;//从0开始（含）
            range[0].End = 180.0F;//到180结束（不含，色调的范围0到180
            int[] channels = new int[] { 0 };//一个通道,初始化为通道0,这些东西可以共用设置

            Mat[] rois = Cv2.Split(roiHSV);//将roi拆分
            Mat[] rois0 = new Mat[] { rois[0] };//roi的第一个通道，也就是H，色调

            Mat mask = new Mat();//掩码;
          
            Mat[] hist = new Mat[] { new Mat() };//一个矩阵数组，用来接收直方图,记得初始化
            Cv2.CalcHist(rois0, channels, mask, hist[0], 1, histsize, range);//把roi的色调通道转换成直方图

            Mat[] srcs = new Mat[] { srcHSV };
            Mat[] histBack = new Mat[] { new Mat() };//返回的反向直方图，一个通道就够
            Cv2.CalcBackProject(srcs, channels, hist[0], histBack[0], range);//输出反向直方图
            Rect rect = new Rect(0, 0, device.Width, device.Height);

            Cv2.MeanShift(histBack[0], ref rect, new TermCriteria(CriteriaType.MaxIter, 10, 0.1));//框大小不会变化，其它一样
                                                                                                  //Cv2.CamShift(HistBack(dst, roi), ref rect, new TermCriteria(CriteriaType.MaxIter, 10, 0.1));//框大小会变化
            source.Rectangle(rect, Scalar.White);//在dst上画框
            Cv2.ImShow("dst", source);
            Cv2.ImShow("src", device);
        }
    }
}
